/*
 * touch.c
 *
 *  Created on: 2012-07-06
 *      Author: byron
 *
 *
 *    Communication with AR1010 9600,8n1
		tx_touch - F1 P0.0 TXD3 (TUART3)
		rx_touch - E1 P0.1 RXD3 (UART3)
 */

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

#include "serial.h"
#include "touch.h"
#include "config.h"
#include "debug.h"

#include "GUI.h"

xSemaphoreHandle xTouchCalibDoneSemaphore;
xQueueHandle xTouchQueue;

static void vTouch_SendData( unsigned char* dataBuf, unsigned char dataSize );
static int xTouch_WaitForResponse( unsigned char* dataBuf, unsigned char respSize, unsigned char headerType, portTickType xTicksToWait );
static int xTouch_Calibrate( void );
static void vTouchTask( void *pvParameters );

static void vTouch_SendData( unsigned char* dataBuf, unsigned char dataSize )
{
	unsigned int i;
	unsigned char dummy;

	if(dataSize==0) return;
	while (xSerialGetChar( TOUCH_UART, &dummy, 5 ) == pdTRUE ); //flush com port
	xSerialPutData( TOUCH_UART, dataBuf, dataSize );
	DEBUGF(DBG_TOUCH, "cmd: ");
	for(i=0; i<dataSize;i++)
		DEBUGF(DBG_TOUCH, "%02X ", dataBuf[i]);
	DEBUGF(DBG_TOUCH, "\n");
}


static int xTouch_WaitForResponse( unsigned char* dataBuf, unsigned char respSize, unsigned char headerType, portTickType xTicksToWait )
{
	unsigned int i;
	unsigned char ucBytesRxed = 0, ucByteRxed;
	unsigned char* ptr = dataBuf;


	while ( ucBytesRxed < respSize )
	{
		if( xSerialGetChar( TOUCH_UART, &ucByteRxed, 5 ) == pdTRUE )
		{
			if((((ucByteRxed == headerType) || (ucByteRxed == headerType+1)) && (ucBytesRxed == 0)) || (ucBytesRxed > 0)) //rozpocznij pobieranie ramki po otrzymaniu właściwego nagłówka
			{
				if(++ucBytesRxed > MAX_RX_TOUCH)
					return pdFAIL;
				//vTaskFeedWD(WD_TOUCH);
				*dataBuf++ = ucByteRxed;
			}
		}
		else
		{
			xTicksToWait-=5;
		}
		if(xTicksToWait == 0)
		{
			break;
		}
	}

	DEBUGF(DBG_TOUCH, "response: ");
	for(i=0; i<respSize;i++)
		DEBUGF(DBG_TOUCH,"%02X ", ptr[i]);
	DEBUGF(DBG_TOUCH, "\n");

	if(xTicksToWait == 0)
	{
		return pdFALSE;
	}

	return pdPASS;
}

void vTouch_Init(void)
{
	vSemaphoreCreateBinary(xTouchCalibDoneSemaphore);
	xSemaphoreTake(xTouchCalibDoneSemaphore, 0);
	xTouchQueue = xQueueCreate(256, (unsigned portBASE_TYPE) sizeof (TTouchPoint));
	vSerialInit(TOUCH_UART, 9600);
	xTaskCreate( vTouchTask, ( signed char * ) "TOUCH", TOUCH_TASK_STACKSIZE, ( void * ) NULL, 3, NULL );
}


static int xTouch_Calibrate( void )
{
	unsigned char sndBuf[MAX_TX_TOUCH];
	unsigned char rcvBuf[MAX_RX_TOUCH];
	unsigned char addr;
	int finish=0;
	int stan=0;
	GUI_DispStringAt("Kalibracja", 160, 120);
	while(finish==0)
	{
		//lprintf("state: %d\n", stan);
		switch (stan)
		{
		case 0: //Disable touch
			sndBuf[0]=0x55;
			sndBuf[1]=0x01;
			sndBuf[2]=0x13;
			vTouch_SendData(sndBuf, 3);
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, 100) != pdPASS)
				stan=11;
			else
			{
				stan=1;
				vTaskDelay(100);
			}
			break;

		case 1:	//Get register group Start address
			sndBuf[0]=0x55;
			sndBuf[1]=0x01;
			sndBuf[2]=0x22;
			vTouch_SendData(sndBuf, 3);
			if(xTouch_WaitForResponse(rcvBuf, 5, TOUCH_HEADER_CMD, 200) != pdPASS)
			{
				stan=11;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=11;
				}
				else
				{
					addr=rcvBuf[4];
					stan=2;
					vTaskDelay(100);
				}
			}
			break;

		case 2:	//Set the Calibration Inset by writing the desired value to the CalibrationInset register <0x55><0x05><0x21><0x00><0x15><0x01><0x19>
			sndBuf[0]=0x55;
			sndBuf[1]=0x05;
			sndBuf[2]=0x21;
			sndBuf[3]=0x00;
			sndBuf[4]=addr+0x0E;
			sndBuf[5]=0x01;
			sndBuf[6]=0x19;
			vTouch_SendData(sndBuf, 7);
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, 200) != pdPASS)
			{
				stan=11;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=11;
				}
				else
				{
					vTaskDelay(100);
					stan=3;
				}
			}
			break;

		case 3: //Issue the <Calibrate Mode> command.
			sndBuf[0]=0x55;
			sndBuf[1]=0x02;
			sndBuf[2]=0x14;
			sndBuf[3]=0x04;
			vTouch_SendData(sndBuf, 4);
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, 200) != pdPASS)
			{
				stan=11;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=11;
				}
				else
				{
					vTaskDelay(100);
					stan=4;
				}
			}
			break;

		case 4:	//Display the first calibration point target in the upper left quadrant
			GUI_DrawCircle(35,25,5);
			//Wait for the user to touch and release the first calibration point target
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, TOUCH_WAIT_CALIB) != pdPASS)
			{
				stan=10;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=11;
				}
				else
				{
					vTaskDelay(100);
					stan=5;
				}
			}
			break;

		case 5:	//Display the second calibration point target in the upper left quadrant
			GUI_Clear();
			GUI_DrawCircle(320-45,25,5);
			//Wait for the user to touch and release the first calibration point target
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, TOUCH_WAIT_CALIB) != pdPASS)
			{
				stan=10;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=11;
				}
				else
				{
					vTaskDelay(100);
					stan=6;
				}
			}
			break;

		case 6:	//Display the third calibration point target in the upper left quadrant
			GUI_Clear();
			GUI_DrawCircle(320-45,240-35,5);
			//Wait for the user to touch and release the first calibration point target
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, TOUCH_WAIT_CALIB) != pdPASS)
			{
				stan=10;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=11;
				}
				else
				{
					vTaskDelay(100);
					stan=7;
				}
			}
			break;

		case 7:	//Display the fourth calibration point target in the upper left quadrant
			GUI_Clear();
			GUI_DrawCircle(35, 240-35,5);
			//Wait for the user to touch and release the first calibration point target
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, TOUCH_WAIT_CALIB) != pdPASS)
			{
				stan=10;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=10;
				}
				else
				{
					vTaskDelay(100);
					stan=8;
				}
			}
			break;

		case 8:	//Wait for write EEPROM
			//vGUI_DrawTouchPointCalibration(4);
			vTaskDelay(1000);
			stan=9;
			break;

		case 9:	//Enable touch reporting by issuing <Enable Touch> command
			sndBuf[0]=0x55;
			sndBuf[1]=0x01;
			sndBuf[2]=0x12;
			vTouch_SendData(sndBuf, 3);
			if(xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, 10000) != pdPASS)
			{
				stan=11;
			}
			else
			{
				if(rcvBuf[2] != TOUCH_RESPONSE_SUCCESS)
				{
					stan=11;
				}
				else
				{
					DEBUGF(DBG_TOUCH, "Touch calibration successfull\n\r");
					vTaskDelay(100);
					return pdPASS;
				}
			}
			break;
		case 10: //Cancel calibration
			//vGUI_DrawTouchPointCalibration(4);
			sndBuf[0]=0x55;
			sndBuf[1]=0x01;
			sndBuf[2]=0x12;
			vTouch_SendData(sndBuf, 3);
			xTouch_WaitForResponse(rcvBuf, 3, TOUCH_HEADER_CMD, 5000);
			stan = 11;
			break;
		case 11: //Error or timeout
			vTaskDelay(1000);
			////Enable touch reporting by issuing <Enable Touch> command
			sndBuf[0]=0x55;
			sndBuf[1]=0x01;
			sndBuf[2]=0x12;
			vTouch_SendData(sndBuf, 3);
			xTouch_WaitForResponse(rcvBuf, 4, TOUCH_HEADER_CMD, 3000);
			if(rcvBuf[2] == TOUCH_RESPONSE_SUCCESS)
			{
				lprintf("Touch no calibration\n\r");
			}
			else
			{
				lprintf("Touch error\n");
			}

			vTaskDelay(100);

			return pdFAIL;
			break;

		default:
			return pdFAIL;
			break;
		}
	}
	return pdFAIL;
}

GUI_PID_STATE State;

static void vTouchTask( void *pvParameters )
{
	TTouchPoint TouchPoint;
	unsigned char rcvBuf[MAX_RX_TOUCH];
	(void) pvParameters;

	//vTaskInitWD(WD_TOUCH);
	xTouch_Calibrate();
	GUI_Clear();
	GUI_DispStringAt("Zakończono", 160, 120);
	xSemaphoreGive(xTouchCalibDoneSemaphore);

	for(;;)
	{
		if(xTouch_WaitForResponse(rcvBuf, 5, TOUCH_HEADER_REPORT, 100) == pdPASS)
		{
			State.Pressed = rcvBuf[0] & 0x01;
			State.x=((double)(((unsigned short)(rcvBuf[1]&0x7F)) | (((unsigned short)(rcvBuf[2]&0x1F))<<7))/4096)*320;
			State.y=((double)(((unsigned short)(rcvBuf[3]&0x7F)) | (((unsigned short)(rcvBuf[4]&0x1F))<<7))/4096)*240;

			GUI_TOUCH_StoreStateEx(&State);
		}
	}
}
